/*
 * {CopyRightNotice}
 */
package com.klondike.common;

import static com.klondike.common.Utils.checkCondition;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

/**
 * @author Sandeep Kadyan
 */
public class Properties extends java.util.Properties {
    private static final long serialVersionUID = 1L;

    private static final int MAX_NESTED_LIMIT = 10;
    private int nestingLevel;

    public Properties(java.util.Properties defaults) {
        this(defaults, MAX_NESTED_LIMIT);
    }

    public Properties(java.util.Properties defaults, int nestingLevel) {
        super(defaults);
        checkCondition(nestingLevel > 0 && nestingLevel <= MAX_NESTED_LIMIT, "invalid nesting limit");
        this.nestingLevel = nestingLevel;
    }

    public Properties() {
        this(null);
    }

    public Properties(int nestedLevel) {
        this(null, nestedLevel);
    }

    // ****************** code-compatible stuff start ******************

    @Override
    public Object put(Object key, Object value) {
        return super.put((String) key, (String) value);
    }

    @Override
    public Object get(Object key) {
        return internalGet((String) key, 0);
    }

    /*
     * Implementation Note:- This method is overridden here because of the wrong
     * implementation in java.util.Property class. The super class should not
     * use super keyword while invoking get() method.
     */
    @Override
    public String getProperty(String key) {
        String sval = (String) get(key);
        return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval;
    }

    // ****************** code-compatible stuff end ******************

    /**
     * This method try to substitute the value from the other key.
     */
    private synchronized String internalGet(String key, int level) {
        // need to check the resolution of the property value.
        // this is different from the java Properties implementation.
        String val = (String) super.get(key);
        if (val == null && defaults != null)
            val = defaults.getProperty(key);

        if (val != null) {
            if (val.length() > 0 && val.charAt(0) == '@') {
                if (level >= nestingLevel)
                    return null;
                String newKey = val.substring(1);
                val = internalGet(newKey, ++level);
            }
        }

        return val;
    }

    @Override
    public void load(InputStream inStream) throws IOException {
        load(new InputStreamReader(inStream, "utf-8"));
    }
}
